﻿package 
{
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.text.*;

// Example illustrating AS3 version of Tonypa's excellent tutorial:
// http://www.tonypa.pri.ee/tbw/tut05.html

public class Main extends Sprite 
{
	private static const TILE_HEIGHT : Number = 32;
	private static const TILE_WIDTH : Number = 32;
	
	private var m_characterCollisionHeight : Number;
	private var m_characterCollisionWidth : Number;
	
	private var m_keyboard : KeyboardListener;
	private var m_character : Sprite;
	private var m_collisionMap : CollisionMap;
	private var m_debugDraw : Sprite;
	
	private var m_characterHorizontalVelocity : int = 0;
	private var m_characterVerticalVelocity : int = 0;
	
	public function Main():void 
	{
		if( stage ) 
		{
			addedToStage();
		}
		else 
		{
			addEventListener(Event.ADDED_TO_STAGE, addedToStage );
		}
	}
	
	private function addedToStage(e:Event = null):void 
	{
		removeEventListener(Event.ADDED_TO_STAGE, addedToStage );
		initialize();
	}
	
	private function initialize() : void
	{
		m_keyboard = new KeyboardListener( this.stage );		
		addChild( new Assets.ROOM_PNG() );			
		
		createCollisionMap();
		createCharacter();
		
		var infoText : TextField = new TextField();
		infoText.textColor = 0xFFFFFF;
		infoText.defaultTextFormat = new TextFormat( "Verdana", 9 );
		infoText.width = this.width;
		infoText.wordWrap = true;
		infoText.selectable = false;
		infoText.text = "Arrows move. Hold space to show collision detection.";
		infoText.filters = [ new DropShadowFilter( 1 ) ];
		infoText.y = this.height - infoText.height;
		addChild( infoText );
		
		this.addEventListener( Event.ENTER_FRAME, tick ); // should use Ticker here, but trying to keep the example simpler
	}
	
	private function createCharacter() : void
	{
		m_character	= new Sprite();
		addChild( m_character );
		
		var characterBitmap : Bitmap = new Assets.CHARACTER_PNG();
		m_character.addChild( characterBitmap );
		characterBitmap.x = -characterBitmap.width / 2; // center horizontally
		characterBitmap.y = -characterBitmap.height + 8; // we want the vertical registration point at her feet			
		
		m_characterCollisionHeight = 8;
		m_characterCollisionWidth = characterBitmap.width - 4;			
		
		m_character.x = 50;
		m_character.y = 156;
	}
	
	private function createCollisionMap() : void
	{
		m_collisionMap = new CollisionMap();
		m_collisionMap.setTraversable( 1, 4, true );
		m_collisionMap.setTraversable( 2, 4, true );
		m_collisionMap.setTraversable( 3, 4, true );
		m_collisionMap.setTraversable( 1, 5, true );
		// m_collisionMap.setTraversable( 2, 5, true ); // this is where the barrel is
		m_collisionMap.setTraversable( 3, 5, true );
		m_collisionMap.setTraversable( 1, 6, true );
		m_collisionMap.setTraversable( 2, 6, true );
		m_collisionMap.setTraversable( 3, 6, true );
	}
	
	private function tick( a_event : Event ) : void
	{
		processKeyboard();			
		
		moveEntity( m_character, m_characterHorizontalVelocity, m_characterVerticalVelocity, m_characterCollisionWidth, m_characterCollisionHeight );
		
		doDebugDraw();
	}		
	
	private function doDebugDraw() : void
	{
		if( m_keyboard.spacebar )
		{
			drawCollisionMap();
		}
		else
		{
			if( m_debugDraw != null )
			{
				m_debugDraw.parent.removeChild( m_debugDraw );
				m_debugDraw = null;
			}
		}			
	}
	
	private function processKeyboard() : void
	{
		// Naughty! We typically want time based movement using velocities
		// Keeping it simple for illustrative purposes
		
		m_characterHorizontalVelocity = 0;
		m_characterVerticalVelocity = 0;
		
		if( m_keyboard.up )
		{
			m_characterVerticalVelocity = -1;
		}
		if( m_keyboard.down )
		{
			m_characterVerticalVelocity = +1;
		}
		if( m_keyboard.left )
		{
			m_characterHorizontalVelocity = -1;
		}
		if( m_keyboard.right )
		{
			m_characterHorizontalVelocity = +1;
		}									
	}
	
	private function drawCollisionMap() : void
	{
		if( m_debugDraw == null )
		{
			m_debugDraw = new Sprite();
			addChild( m_debugDraw );
		}
		
		m_debugDraw.graphics.clear();
		m_debugDraw.graphics.beginFill( 0x00FF00, 0.5 );
		
		for( var c : int = 0; c < m_collisionMap.columnSize; c++ )
		{
			for( var r : int = 0; r < m_collisionMap.rowSize; r++ )
			{						
				var traversable : Boolean = m_collisionMap.isTraversable( c, r );
				if( traversable )
				{
					m_debugDraw.graphics.drawRect( c * TILE_WIDTH, r * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT );
				}
			}
		}
		
		m_debugDraw.graphics.beginFill( 0x0000FF, 0.8 );
		m_debugDraw.graphics.drawRect( m_character.x - m_characterCollisionWidth / 2, m_character.y - m_characterCollisionHeight / 2, m_characterCollisionWidth, m_characterCollisionHeight );
	}
	
	private function moveEntity( a_entity : Sprite, a_horizontalVelocity : Number, a_verticalVelocity : Number, a_collisionWidth : Number, a_collisionHeight : Number ):void 
	{			
		var tileX : int = Math.floor( a_entity.x / TILE_WIDTH );
		var tileY : int = Math.floor( a_entity.y / TILE_HEIGHT );
		
		// We check for collisions against the collision map for where we might end up
		// First we check the vertical velocity
		var tileLeft : int = Math.floor( (a_entity.x - a_collisionWidth / 2) / TILE_WIDTH );
		var tileRight : int = Math.floor( (a_entity.x + a_collisionWidth / 2 - 1 ) / TILE_WIDTH ); // - 1 is necessary ;)
		var tileTop : int = Math.floor( (a_entity.y - a_collisionHeight / 2 + a_verticalVelocity) / TILE_HEIGHT );
		var tileBottom : int = Math.floor( (a_entity.y + a_collisionHeight / 2 + a_verticalVelocity - 1) / TILE_HEIGHT ); // - 1 is necessary ;)
		
		var leftTopTraversable : Boolean = m_collisionMap.isTraversable( tileLeft, tileTop );
		var rightTopTraversable : Boolean = m_collisionMap.isTraversable( tileRight, tileTop );
		var leftBottomTraversable : Boolean = m_collisionMap.isTraversable( tileLeft, tileBottom );
		var rightBottomTraversable : Boolean = m_collisionMap.isTraversable( tileRight, tileBottom );
		
		if( a_verticalVelocity < 0 ) 
		{
			if( leftTopTraversable && rightTopTraversable ) 
			{
				a_entity.y += a_verticalVelocity;
			} 
			else 
			{
				a_entity.y = tileY * TILE_HEIGHT + a_collisionHeight/2;
			}
		}
		if( a_verticalVelocity > 0 ) 
		{
			if ( leftBottomTraversable && rightBottomTraversable ) 
			{
				a_entity.y += a_verticalVelocity;
			} 
			else 
			{
				a_entity.y = (tileY + 1) * TILE_HEIGHT - a_collisionHeight/2;
			}
		}

		// Now check horizontal velocity
		tileLeft = Math.floor( (a_entity.x - a_collisionWidth / 2 + a_horizontalVelocity ) / TILE_WIDTH );
		tileRight = Math.floor( (a_entity.x + a_collisionWidth / 2 + a_horizontalVelocity -1 ) / TILE_WIDTH ); // - 1 is necessary ;)
		tileTop = Math.floor( (a_entity.y - a_collisionHeight / 2 ) / TILE_HEIGHT );
		tileBottom = Math.floor( (a_entity.y + a_collisionHeight / 2  - 1) / TILE_HEIGHT ); // - 1 is necessary ;)
		
		leftTopTraversable = m_collisionMap.isTraversable( tileLeft, tileTop );
		rightTopTraversable = m_collisionMap.isTraversable( tileRight, tileTop );
		leftBottomTraversable = m_collisionMap.isTraversable( tileLeft, tileBottom );
		rightBottomTraversable = m_collisionMap.isTraversable( tileRight, tileBottom );
		
		if( a_horizontalVelocity < 0 ) 
		{
			if ( leftBottomTraversable && leftTopTraversable ) 
			{
				a_entity.x += a_horizontalVelocity;
			} 
			else 
			{
				a_entity.x = tileX * TILE_WIDTH + a_collisionWidth / 2;
			}
		}
		
		if( a_horizontalVelocity > 0 ) 
		{
			if ( rightTopTraversable && rightBottomTraversable ) 
			{
				a_entity.x += a_horizontalVelocity;
			} 
			else 
			{
				a_entity.x = ( tileX + 1) * TILE_WIDTH - a_collisionWidth / 2;
			}
		}
	}
}
	
}